package cn.tedu.adminsystem.webapi.service.impl;

import cn.tedu.adminsystem.service.IAdmService;
import cn.tedu.adminsystem.service.PhotoUploadService;
import cn.tedu.adminsystem.webapi.mapper.AdmMapper;
import cn.tedu.adminsystem.webapi.mapper.AdmRoleMapper;
import cn.tedu.adminsystem.webapi.security.AdminDetails;
import cn.tedu.adminsystem.webapi.security.CurrentAdmin;
import cn.tedu.community.commons.excepion.ServiceException;
import cn.tedu.community.commons.pojo.admRole.entity.AdminRole;
import cn.tedu.community.commons.pojo.admin.dto.*;
import cn.tedu.community.commons.pojo.admin.entity.Admin;
import cn.tedu.community.commons.pojo.admin.vo.AdminListItemVO;
import cn.tedu.community.commons.pojo.admin.vo.AdminStandardVO;
import cn.tedu.community.commons.restful.JsonPage;
import cn.tedu.community.commons.restful.ServiceCode;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Slf4j
@Service
public class AdmServiceImpl implements IAdmService {

    @Value("${community.jwt.secret-key}")
    private String secretKey;
    @Value("${community.jwt.duration-in-minute}")
    private long durationInMinute;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AdmMapper admMapper;
    @Autowired
    private AdmRoleMapper admRoleMapper;
    @Autowired
    private PhotoUploadService photoUploadService;

    @Override
    public String login(AdminLoginDTO loginDTO) {
        log.debug("开始处理【管理员登录】的业务，参数：{}", loginDTO);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                loginDTO.getAdmName(), loginDTO.getAdmPassword());
        Authentication authenticationResult = authenticationManager.authenticate(authentication);
        log.debug("认证通过，认证结果：{}", authenticationResult);
        log.debug("认证通过，认证结果中的当事人：{}", authenticationResult.getPrincipal());

        //将通过认证的管理员的相关信息存入到JWT中
        //准备生成JWT的相关数据
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        AdminDetails principal = (AdminDetails) authenticationResult.getPrincipal();
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", principal.getId());
        claims.put("username", principal.getUsername());
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);
        claims.put("authoritiesJsonString", authoritiesJsonString);

        //生成JWT
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // data
                .setClaims(claims)
                // 生命周期
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                //完成
                .compact();
        //返回JWT
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO addNewDTO) {
        Long[] roles = addNewDTO.getRoleIds();
        for (int i = 0; i < roles.length; i++) {
            if (roles[i] == 1) {
                String message = "添加管理员失败，禁止添加系统管理员!";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        int countByAdmName = admMapper.countByAdmName(addNewDTO.getAdmName());
        if (countByAdmName > 0) {
            String message = "添加管理员失败，管理员用户名已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        int countByPhone = admMapper.countByPhone(addNewDTO.getPhone());
        if (countByPhone > 0) {
            String message = "添加管理员失败，管理员手机号已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        int countByEmail = admMapper.countByEmail(addNewDTO.getEmail());
        if (countByEmail > 0) {
            String message = "添加管理员失败，管理员电子邮箱已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(addNewDTO, admin);
        admin.setLoginCount(0);
        String rawPassword = admin.getAdmPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setAdmPassword(encodedPassword);
        int insertRows = admMapper.insert(admin);
        if (insertRows != 1) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        AdminRole[] adminRoles = new AdminRole[roles.length];
        for (int i = 0; i < adminRoles.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roles[i]);
            adminRoles[i] = adminRole;
        }
        int insertBatchRows = admRoleMapper.insertBatch(adminRoles);
        if (insertBatchRows != adminRoles.length) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public void insertBatch(AdminAddNewDTO[] addNewDTOs) {
        // 超简便写法，直接调用上面addNew()方法即可
//      for (AdminAddNewDTO addNewDTO : addNewDTOs) {
//          addNew(addNewDTO);
//      }

        //学习阶段，自行扩展写法,有bug
        Admin[] admins = new Admin[addNewDTOs.length];
        Long[] roleIds = null;
        for (int j = 0; j < admins.length; j++) {
            roleIds = addNewDTOs[j].getRoleIds();
            int roleLength = roleIds.length;
            if (roleLength < 1) {
                String message = "添加【" + addNewDTOs[j].getAdmName() + "】管理员失败，请选择管理员角色！";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
            for (int i = 0; i < roleLength; i++) {
                if (roleIds[i] == 1) {
                    String message = "添加管理员失败，禁止添加该管理员！";
                    throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
                }
            }
            int countByAdmName = admMapper.countByAdmName(addNewDTOs[j].getAdmName());
            if (countByAdmName > 0) {
                String message = "添加管理员失败，管理员用户名已被占用!";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }

            int countByPhone = admMapper.countByPhone(addNewDTOs[j].getPhone());
            if (countByPhone > 0) {
                String message = "添加管理员失败，管理员手机号已被占用!";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }

            int countByEmail = admMapper.countByEmail(addNewDTOs[j].getEmail());
            if (countByEmail > 0) {
                String message = "添加管理员失败，管理员电子邮箱已被占用!";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }

            Admin admin = new Admin();
            BeanUtils.copyProperties(addNewDTOs[j], admin);
            admin.setLoginCount(0);
            String rawPassword = admin.getAdmPassword();
            String encodedPassword = passwordEncoder.encode(rawPassword);
            admin.setAdmPassword(encodedPassword);
            admins[j] = admin;

        }
        int insertBatchRows = admMapper.insertBatch(admins);
        if (insertBatchRows != admins.length) {
            String message = "添加管理员失败，服务器繁忙！";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
        AdminRole[] adminRoles = new AdminRole[admins.length];
        for (int i = 0; i < adminRoles.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admins[i].getId());
            adminRole.setRoleId(roleIds[i]);
            adminRoles[i] = adminRole;
        }
        int admRoleInsertRows = admRoleMapper.insertBatch(adminRoles);
        if (admRoleInsertRows != adminRoles.length) {
            String message = "添加管理员失败，服务器繁忙！";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public JsonPage<AdminListItemVO> list(Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<AdminListItemVO> list = admMapper.list();
        //遍历删除，在分页后不起作用，供参考
        /*Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()) {
            AdminListItemVO admin = iterator.next();
            if (admin.getId() == 1) {
                iterator.remove();
                break;
            }
        }*/
        return JsonPage.restPage(new PageInfo<>(list));
    }

    @Override
    public void deleteById(Long id) {
        if (id == 1) {
            String message = "删除管理员失败，禁止访问！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        AdminStandardVO standardVO = admMapper.getStandardById(id);
        if (standardVO == null) {
            String message = "删除管理员失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }

        int deleteRows = admMapper.deleteById(id);
        if (deleteRows != 1) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        int deleteByAdmId = admRoleMapper.deleteByAdmId(id);
        int countByAdminId = admRoleMapper.countByAdminId(id);
        if (deleteByAdmId < countByAdminId) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        if (standardVO.getAvatar() != null) {
            photoUploadService.deletePhoto(standardVO.getAvatar());
        }
    }

    @Override
    public void deleteIds(Long[] ids) {
        for (Long id : ids) {
            if (id == 1) {
                String message = "删除管理员失败，禁止访问！";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
            AdminStandardVO standardVO = admMapper.getStandardById(id);
            if (standardVO == null) {
                String message = "抱歉，有某些(个)管理员已不存在，请刷新页面后重新选择删除！";
                throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
            }

            int deleteByAdmId = admRoleMapper.deleteByAdmId(id);
            int countByAdminId = admRoleMapper.countByAdminId(id);
            if (deleteByAdmId < countByAdminId) {
                String message = "删除管理员失败，服务器忙，请稍后再尝试！";
                throw new ServiceException(ServiceCode.ERR_DELETE, message);
            }
            if (standardVO.getAvatar() != null) {
                photoUploadService.deletePhoto(standardVO.getAvatar());
            }
        }

        int deleteIdsRows = admMapper.deleteByIds(ids);
        if (deleteIdsRows != ids.length) {
            String message = "删除管理员失败，服务器忙，请稍后再尝试！";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    @Override
    public void update(Long id, AdminUpdateDTO updateDTO) {
        Long[] roleIds = updateDTO.getRoleIds();
        for (int i = 0; i < roleIds.length; i++) {
            if (roleIds[i] == 1) {
                String message = "添加管理员失败，禁止添加系统管理员!";
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        AdminStandardVO standardById = admMapper.getStandardById(id);
        if (standardById == null) {
            String message = "更新管理员信息失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }

        int count = admMapper.countByAdmNameAndNotId(updateDTO.getAdmName(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员用户名已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        count = admMapper.countByPhoneAndNotId(updateDTO.getPhone(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员手机号已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        count = admMapper.countByEmailAndNotId(updateDTO.getEmail(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员电子邮箱已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(updateDTO, admin);
        admin.setId(id);
        int updateRows = admMapper.update(admin);
        if (updateRows != 1) {
            String message = "更新管理员失败，服务器繁忙！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

        int roleByAdminId = admRoleMapper.countByAdminId(admin.getId());
        int update = admRoleMapper.deleteByAdmId(admin.getId());
        if (update < roleByAdminId) {
            String message = "更新管理员失败，服务器繁忙，请稍后重试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

        AdminRole[] adminRoles = new AdminRole[roleIds.length];
        for (int i = 0; i < adminRoles.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRoles[i] = adminRole;
        }
        int insertBatchRows = admRoleMapper.insertBatch(adminRoles);
        if (insertBatchRows != adminRoles.length) {
            String message = "添加管理员失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        if (standardById.getAvatar() != null && !updateDTO.getAvatar().equals(standardById.getAvatar())) {
            photoUploadService.deletePhoto(standardById.getAvatar());
        }
    }

    @Override
    public void updateCurrent(AdminUpdateCurrentDTO updateCurrentDTO) {
        Long id = CurrentAdmin.getAdminId();
        AdminStandardVO standardById = admMapper.getStandardById(id);
        if (standardById == null) {
            String message = "更新管理员信息失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }

        int count = admMapper.countByAdmNameAndNotId(updateCurrentDTO.getAdmName(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员用户名已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        count = admMapper.countByPhoneAndNotId(updateCurrentDTO.getPhone(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员手机号已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        count = admMapper.countByEmailAndNotId(updateCurrentDTO.getEmail(), id);
        if (count > 0) {
            String message = "修改管理员失败，管理员电子邮箱已被占用!";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(updateCurrentDTO, admin);
        admin.setId(id);
        int updateRows = admMapper.update(admin);
        if (updateRows != 1) {
            String message = "更新管理员失败，服务器繁忙！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        if (standardById.getAvatar() != null && !updateCurrentDTO.getAvatar().equals(standardById.getAvatar())) {
            photoUploadService.deletePhoto(standardById.getAvatar());
        }
    }

    @Override
    public void updatePass(AdminUpdatePassDTO updatePassDTO) {
        Long adminId = CurrentAdmin.getAdminId();
        String oldPassword = admMapper.getOldPassword(adminId);
        if (!passwordEncoder.matches(updatePassDTO.getOldPassword(), oldPassword)) {
            throw new ServiceException(ServiceCode.ERR_SELECT, "原密码不正确，请重新输入！");
        }
        if (!updatePassDTO.getNewPassword().equals(updatePassDTO.getConfirmPassword())) {
            throw new ServiceException(ServiceCode.ERR_SELECT, "两次新密码输入不一致，请重新输入！");
        }
        String encodePassword = passwordEncoder.encode(updatePassDTO.getNewPassword());
        int updatePass = admMapper.updatePass(adminId, encodePassword);
        if (updatePass != 1) {
            throw new ServiceException(ServiceCode.ERR_UPDATE, "服务器繁忙，请稍后再试！");
        }
        SecurityContextHolder.clearContext();
    }

    @Override
    public void setEnable(Long id) {
        setEnableOrDisable(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        setEnableOrDisable(id, 0);
    }

    private void setEnableOrDisable(Long id, Integer enable) {
        String[] enableText = {"禁用", "启用"};

        AdminStandardVO standardById = admMapper.getStandardById(id);
        if (standardById == null) {
            String message = "【" + enableText[enable] + "】管理员失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }
        if (standardById.getEnable() == enable) {
            String message = "【" + enableText[enable] + "】管理员失败，管理员已是【" + enableText[enable] + "】状态";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        int updateRows = admMapper.update(admin);
        if (updateRows != 1) {
            String message = "【" + enableText[enable] + "】失败，服务器繁忙，请稍后重试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public AdminStandardVO getStandard() {
        Long adminId = CurrentAdmin.getAdminId();
        log.debug("当前id是：{}", adminId);
        AdminStandardVO standardById = admMapper.getStandardById(adminId);
        if (standardById == null) {
            String message = "查询管理员详情失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }
        return standardById;
    }

    @Override
    public AdminStandardVO getStandardById(Long id) {
        AdminStandardVO standardById = admMapper.getStandardById(id);
        if (standardById == null) {
            String message = "查询管理员详情失败，管理员不存在！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }
        return standardById;
    }
}
